/***************************************************************
* gfsConsole : Console to access GFS user-library
*
* @author : Ridho B - 0606101906
* @version : 1.0
*
***************************************************************/
#define _FILE_OFFSET_BITS 64 // To handle transfer large file (> 2GB)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "gfsGlobal.h"
#include "gfsLibrary.h"

#define MAXWORKINGPATH   600
#define MAXCMDLENGTH  10
#define MAXPARAMS 2
#define MAXPARAMSLENGTH 512
//#define BUFFER_SIZE 512000 // ?
int BUFFER_SIZE = 5000000; // FOR TESTING PURPOSE

// ALL FUNCTION //
int gfs_init();					/* ANSI function prototype */
void print_help();				/* ANSI function prototype */
void gfs_put(char*);				/* ANSI function prototype */
void gfs_get(char*);				/* ANSI function prototype */
void gfs_ls(char, char*);			/* ANSI function prototype */
void gfs_cd(char*);				/* ANSI function prototype */
void gfs_rm_f(char*);				/* ANSI function prototype */
void gfs_rm_d(char*);				/* ANSI function prototype */
void gfs_rm_recrsv(char *);			/* ANSI function prototype */
void gfs_mv(char*, char*);			/* ANSI function prototype */
void gfs_mkdir(char*);				/* ANSI function prototype */
void gfs_debug(char*);				/* ANSI function prototype */
void gfs_show(char*);				/* ANSI function prototype */
void gfs_bash(char*);				/* ANSI function prototype */
void gfs_chmod(char*, char*);		/* ANSI function prototype */
void gfs_superuser(char*);			/* ANSI function prototype */

char getchar_until_next(char* , int);		/* ANSI function prototype */
void getchar_until_end(char* , int);		/* ANSI function prototype */
void getpswd(char*, int);			/* ANSI function prototype */
void get_full_path(char*, char*, char*);	/* ANSI function prototype */
void get_file_name(char*, char*);		/* ANSI function prototype */
int  select_cmd(char* );			/* ANSI function prototype */
void process_param(char*, char*);		/* ANSI function prototype */
void show_server();				/* ANSI function prototype */
void advance_cursor();


// COMMANDS //
char *arrCommands[] = {
		"help",
		"put",
		"get",
		"ls",
		"cd",
		"rm",
		"mv",
		"mkdir",
		"rmdir",
		"debug",
		"show",
		"chmod",
		"su",
		"exit",
		"testput",
		"testget"
		};

// WORKING PATH //
char strWorkingPath[MAXWORKINGPATH];

// MAIN //
int main()
{
	// INIT GFS	//
	if(!gfs_init())
		return 0;
		
	// 	READY	//
	printf("\n\n==========:. GRID FILE SYSTEM .:==========\n");
	
	// DEFINE VARIABLE //
	char    chInput;               				/* handles user input */
	char    strCmd[MAXCMDLENGTH];				/* String Command, max 10 chr */
	char    strParams01[MAXPARAMSLENGTH];			/* Array of String Params, max 512 chr */
	char    strParams02[MAXPARAMSLENGTH];			/* Array of String Params, max 512 chr */
	char    strUnusdParams[MAXPARAMSLENGTH];		/* Array of String Params that Unused, max 512 chr */
	int     iExit_flag = 0;					/* Flag for exit command*/
	int     iNotValid = 0;					/* Flag for not valid command and operands */
	int     iParams;					/* Number of params */
	int 	iIdx;						/* Index */
	
	// SET PATH FOR ROOT //
	strcpy(strWorkingPath,"/");
	
	// EXECUTE COMMAND //
	while( iExit_flag == 0 ) {
		/* initiate */
		strCmd[0] = 0x00;
		strParams01[0] = 0x00;
		strParams02[0] = 0x00;
		strUnusdParams[0] = 0x00;
		iNotValid = 0;
		iParams = 0;
		
		/* begin */
		printf("gfs<:%s# ", strWorkingPath);
		
		/* Get Command */
		chInput = getchar_until_next(strCmd, MAXCMDLENGTH);
		
		/* Identify Command */
		if(strCmd[0] == '!'){// BASH COMMAND
			if(chInput != '\n')
				getchar_until_end(strParams01, MAXPARAMSLENGTH);
			strcat(strCmd, " ");
			strcat(strCmd, strParams01);
			gfs_bash(strCmd+1);
			continue;
		}
		switch( iIdx = select_cmd(strCmd)) {
			case 0: /* help -------------------------------------------------------------help---*/
				if(chInput != '\n')
					getchar_until_end(strUnusdParams, MAXPARAMSLENGTH);
				print_help();
				break;
			case 1: /* put  -------------------------------------------------------------put----*/
				/* Get Params */
				if(chInput != '\n'){
					iParams++;
					chInput = getchar_until_next(strParams01, MAXPARAMSLENGTH);
				}/*
				if(chInput != '\n'){
					iParams++;
					chInput = getchar_until_next(strParams02, MAXPARAMSLENGTH);
				}*/
				if(chInput != '\n')
					getchar_until_end(strUnusdParams, MAXPARAMSLENGTH);
				/* Valid Params*/
				if(iParams <1) 
					iNotValid = 1;
				else
					gfs_put(strParams01); /** call command function **/
				break;
			case 2: /* get  --------------------------------------------------------------get---*/
				/* Get Params */
				if(chInput != '\n'){
					iParams++;
					chInput = getchar_until_next(strParams01, MAXPARAMSLENGTH);
				}/*
				if(chInput != '\n'){
					iParams++;
					chInput = getchar_until_next(strParams02, MAXPARAMSLENGTH);
				}*/
				if(chInput != '\n')
					getchar_until_end(strUnusdParams, MAXPARAMSLENGTH);
				/* Valid Params*/
				if(iParams <1) 
					iNotValid = 1;
				else
					gfs_get(strParams01); /** call command function **/
				break;
			case 3: /* ls  ---------------------------------------------------------------ls----*/
				/* Get Params */
				if(chInput != '\n'){
					iParams++;
					chInput = getchar_until_next(strParams01, MAXPARAMSLENGTH);
				}
				if(chInput != '\n'){
					iParams++;
					chInput = getchar_until_next(strParams02, MAXPARAMSLENGTH);
				}
				if(chInput != '\n')
					getchar_until_end(strUnusdParams, MAXPARAMSLENGTH);					
				if(!strcmp(strParams01,"-l"))						
					gfs_ls('d', strParams02);/** call command function **/						
				else if(!strcmp(strParams02,"-l"))						
					gfs_ls('d', strParams01);/** call command function **/					
				else 					
					gfs_ls('l', strParams01);/** call command function **/
				
				break;
			case 4: /* cd  ---------------------------------------------------------------cd----*/
				/* Get Params */
				if(chInput != '\n'){
					iParams++;
					chInput = getchar_until_next(strParams01, MAXPARAMSLENGTH);
				}
				if(chInput != '\n')
					getchar_until_end(strUnusdParams, MAXPARAMSLENGTH);
				/* Valid Params*/
				if(iParams <1) 
					iNotValid = 1;
				else
					gfs_cd(strParams01); /** call command function **/
				break;
			case 5: /* rm  ---------------------------------------------------------------rm---*/
				/* Get Params */
				if(chInput != '\n'){
					iParams++;
					chInput = getchar_until_next(strParams01, MAXPARAMSLENGTH);
				}
				if((chInput != '\n') && !(strcmp(strParams01, "-R"))){
					iParams++;
					chInput = getchar_until_next(strParams02, MAXPARAMSLENGTH);
				}
				if(chInput != '\n')
					getchar_until_end(strUnusdParams, MAXPARAMSLENGTH);
				/* Valid Params*/
				if(!strcmp(strParams01, "-R"))
					if(iParams <2)
						iNotValid = 1;
					else
						gfs_rm_recrsv(strParams02); /** call command function **/
				else 
					if(iParams<1)
						iNotValid = 1;
					else
						gfs_rm_f(strParams01); /** call command function **/
					
				break;
			case 6: /* mv  ---------------------------------------------------------------mv---*/
				/* Get Params */
				if(chInput != '\n'){
					iParams++;
					chInput = getchar_until_next(strParams01, MAXPARAMSLENGTH);
				}
				if((chInput != '\n')){
					iParams++;
					chInput = getchar_until_next(strParams02, MAXPARAMSLENGTH);
				}
				if(chInput != '\n')
					getchar_until_end(strUnusdParams, MAXPARAMSLENGTH);
				/* Valid Params*/
				if(iParams <2)
					iNotValid = 1;
				else
					gfs_mv(strParams01, strParams02); /** call command function **/									
				break;
			case 7: /* mkdir ------------------------------------------------------------mkdir-*/
				/* Get Params */
				if(chInput != '\n'){
					iParams++;
					chInput = getchar_until_next(strParams01, MAXPARAMSLENGTH);
				}
				if(chInput != '\n')
					getchar_until_end(strUnusdParams, MAXPARAMSLENGTH);
				/* Valid Params*/
				if(iParams <1) 
					iNotValid = 1;
				else
					gfs_mkdir(strParams01); /** call command function **/
				break;
			case 8: /* rmdir  -----------------------------------------------------------rmdir-*/
				/* Get Params */
				if(chInput != '\n'){
					iParams++;
					chInput = getchar_until_next(strParams01, MAXPARAMSLENGTH);
				}
				if((chInput != '\n') && !(strcmp(strParams01, "-R"))){
					iParams++;
					chInput = getchar_until_next(strParams02, MAXPARAMSLENGTH);
				}
				if(chInput != '\n')
					getchar_until_end(strUnusdParams, MAXPARAMSLENGTH);
				/* Valid Params*/
				if(!strcmp(strParams01, "-R"))
					if(iParams <2)
						iNotValid = 1;
					else
						gfs_rm_d(strParams02); /** call command function **/
				else 
					if(iParams<1)
						iNotValid = 1;
					else
						gfs_rm_d(strParams01); /** call command function **/					
				break;
			case 9: /* debug --------------------------------------------------------------debug--*/
				if(chInput != '\n')
					getchar_until_end(strParams01, MAXPARAMSLENGTH);
				gfs_debug(strParams01);
				break;
			case 10: /* show ---------------------------------------------------------------show--*/
				if(chInput != '\n')
					getchar_until_end(strParams01, MAXPARAMSLENGTH);
				gfs_show(strParams01);
				break;
			case 11: /* chmod -------------------------------------------------------------chmod--*/				
				if(chInput != '\n'){
					iParams++;
					chInput = getchar_until_next(strParams01, MAXPARAMSLENGTH);
				}
				if((chInput != '\n')){
					iParams++;
					chInput = getchar_until_next(strParams02, MAXPARAMSLENGTH);
				}
				if(chInput != '\n')
					getchar_until_end(strUnusdParams, MAXPARAMSLENGTH);
				/* Valid Params*/				
				gfs_chmod(strParams01, strParams02);
				break;
			case 12: /* su -----------------------------------------------------------superuser--*/				
				if(chInput != '\n'){
					iParams++;
					chInput = getchar_until_next(strParams01, MAXPARAMSLENGTH);
				}
				if(chInput != '\n')
					getchar_until_end(strUnusdParams, MAXPARAMSLENGTH);
				/* Valid Params*/				
				gfs_superuser(strParams01);
				break;
			case 13: /* exit --------------------------------------------------------------exit--*/
				iExit_flag = 1;
				if(chInput != '\n')
					getchar_until_end(strUnusdParams, MAXPARAMSLENGTH);
				break;
			case 14: /* testput ---------------------------------------------------------testput--*/				
				if(chInput != '\n'){
					iParams++;
					chInput = getchar_until_next(strParams01, MAXPARAMSLENGTH);
				}
				if(chInput != '\n')
					getchar_until_end(strUnusdParams, MAXPARAMSLENGTH);
				/* Run Loop Testing*/
				int iCase = 1;
				if(1){
					BUFFER_SIZE = 512000;
					printf("BUFFER = %d -------------------------------------------\n", BUFFER_SIZE);
					for(iCase = 1; iCase < 11; iCase++){
						printf("-try *%d\n", iCase);
						gfs_put(strParams01);
						gfs_rm_f(strParams01);
					}
				}
				BUFFER_SIZE = 1000000;
				while(BUFFER_SIZE < 10000000){
					printf("BUFFER = %d -------------------------------------------\n", BUFFER_SIZE);
					for(iCase = 1; iCase < 11; iCase++){
						printf("-try *%d\n", iCase);
						gfs_put(strParams01);
						gfs_rm_f(strParams01);
					}
					BUFFER_SIZE = BUFFER_SIZE +1000000;
				}
				break;
			case 15: /* testget ---------------------------------------------------------testget--*/				
				if(chInput != '\n'){
					iParams++;
					chInput = getchar_until_next(strParams01, MAXPARAMSLENGTH);
				}
				if(chInput != '\n')
					getchar_until_end(strUnusdParams, MAXPARAMSLENGTH);
				/* Run Loop Testing*/
				BUFFER_SIZE = 5000000;
				CHUNKS = 1;
				iCase = 1;
				if(0){
					gfs_put(strParams01);
				}
				while(CHUNKS < 10){
					printf("CHUNKS = %d -------------------------------------------\n", CHUNKS);
					for(iCase = 1; iCase < 11; iCase++){
						printf("-try *%d\n", iCase);
						gfs_get(strParams01);
					}
					CHUNKS = CHUNKS +1;
				}
				break;
			default:
				if(chInput != '\n')
					getchar_until_end(strUnusdParams, MAXPARAMSLENGTH);
				printf("unknown command, please use help\n");
			break;
		}
		if(iNotValid == 1)
			printf("|X| Missing operand, use help instead!\n");
		
		//*DEBUG*/printf("\nCommand: %s", arrCommands[iIdx]);		
		//*DEBUG*/printf("\nParams01: %s", strParams01);			
		//*DEBUG*/printf("\nParams02: %s", strParams02);			
		//*DEBUG*/printf("\nUnused Params: %s\n\n", strUnusdParams);
	}
	return 0;
}

// INITIALIZATION FUNCTION //
int gfs_init(){
	if(!gfs_init_GFS())
		return 0;
	if(!gfs_init_RNS())
		return 0;
		
	//all init success*
	return 1;
}


// COMMAND FUNCTION //

/**********************************************************************************
* print_help: print menu of gfs
* @params : void
* @return : void
***********************************************************************************/
void print_help(){
	printf(" =================== GFS COMMAND ===================\n");
	printf(" gfs<:# cd [DIRECTORY PATH]\n");
	printf(" gfs<:# chmod [MODE] [GFS PATH]\n");
	printf(" gfs<:# debug [on / off]\n");
	printf(" gfs<:# exit \n");
	printf(" gfs<:# get [GFS FILE PATH]\n");
	printf(" gfs<:# help \n");
	printf(" gfs<:# ls [OPTION*] [DIRECTORY PATH*]\n");
	printf(" gfs<:# mkdir [GFS DIRECTORY PATH]\n");
	printf(" gfs<:# mv [OLD PATH] [NEW PATH]\n");
	printf(" gfs<:# put [LOCAL FILE PATH] \n");
	printf(" gfs<:# rm [OPTION*] [GFS PATH] \n");
	printf(" gfs<:# rmdir [GFS DIRECTORY PATH] \n");
	printf(" gfs<:# show server \n");
	printf(" gfs<:# su [on / off / chpwd] \n");
	printf("                                          *optional \n");
	printf(" ===================================================\n");
}
void gfs_put(char *strSourceFile){
	int				iRead;
	int 	    	iStatus;
	GFS_file    	GFS_file;
    	FILE        	*local_file = NULL;
	char		strName[MAX_NAME];	
    	char		strGFSPath[MAX_PATH];
	time_t 		tend, tstart;
    
    	get_file_name(strSourceFile, strName);	
    	get_full_path(strWorkingPath, strName, strGFSPath);
    	
	time(&tstart); // START EXECUTION TIME

	//STEP 1: OPEN FILE*
	iStatus = gfs_open_file(strGFSPath, "w", &GFS_file);
	if(iStatus != GFS_SUCCESS){ 
		printf("|X| put: %s\n", gfs_get_error(iStatus));
		return;
	}
    	local_file = fopen(strSourceFile, "r");
    	if (local_file == NULL) {
	    printf("|X| put: Can't Open file: %s\n", strSourceFile);
    	}
    
	//STEP 2: WRITE*
	unsigned char	buffer[BUFFER_SIZE];
	printf("processing....");
	while(local_file != NULL && !feof(local_file)){
	advance_cursor();
		iRead = fread(buffer, 1, BUFFER_SIZE, local_file);
		if(ferror(local_file)) { 
			printf("|X| put: Error Transfer from local file");
			break;
		}
		iStatus = gfs_write_file(GFS_file, buffer, iRead);
		if(iStatus <= GFS_FAILED) { 
			printf("|X| put: %s\n", gfs_get_error(iStatus));
			break;
		}
	}    
	//STEP 3: CLOSE FILE*
	gfs_close_file(&GFS_file);	 
   	if(local_file != NULL)
		fclose(local_file);
    	if(iStatus != GFS_SUCCESS){ 
		printf("|X| put: %s\n", gfs_get_error(iStatus));
		return;
	}


	time(&tend); // END EXECUTION TIME
	printf("PUT_GFS_TRANSFER on (%f - %f) = %f seconds\n", (double)tend,  (double)tstart, (double)difftime(tend,tstart));
	//printf("PUT_GFS_TRANSFER on (%f - %f)/%f = %f seconds\n", (double)tend,  (double)tstart, (double)CLOCKS_PER_SEC, ((double)(tend - tstart) / (double)CLOCKS_PER_SEC));
	
}
void gfs_get(char *strDestFile){
	int 	    	iStatus;
	GFS_file    	GFS_file;
    	FILE        	*local_file = NULL;
	char		strName[MAX_NAME];	
    	char		strGFSPath[MAX_PATH];
	time_t 	tend, tstart;
    
    	get_file_name(strDestFile, strName);	
    	get_full_path(strWorkingPath, strName, strGFSPath);
    	
	time(&tstart); // START EXECUTION TIME
    
	//STEP 1: OPEN FILE*
	iStatus = gfs_open_file(strGFSPath, "r", &GFS_file);
	if(iStatus != GFS_SUCCESS){ 
		printf("|X| get: %s\n", gfs_get_error(iStatus));
		return;
	}
    	local_file = fopen(strDestFile, "w");
    	if (local_file == NULL) {
	    printf("|X| get: Can't Open file: %s\n", strDestFile);
    	}
	
	//STEP 2: READ*
	unsigned char	buffer[BUFFER_SIZE];
	printf("processing....");
	while( local_file != NULL && !gfs_end_file(GFS_file)){	
	advance_cursor();	
		iStatus = gfs_read_file(GFS_file, buffer, BUFFER_SIZE);
		if(iStatus <= GFS_FAILED) { 
			printf("|X| get: %s\n", gfs_get_error(iStatus));
			break;
		}	
		fwrite(buffer, 1, iStatus, local_file);
		if(ferror(local_file)) { 
			printf("|X| get: Error Transfer to local file");
			break;
		}	
	}

	//STEP 3: CLOSE FILE*	
	if(local_file != NULL)
		fclose(local_file);
	gfs_close_file(&GFS_file);
    	if(iStatus <= GFS_FAILED){ 
		printf("|X| get: %s\n", gfs_get_error(iStatus));
		return;
	}


	time(&tend); // END EXECUTION TIME
	printf("GET_GFS_TRANSFER on (%f - %f) = %f seconds\n", (double)tend,  (double)tstart, (double)difftime(tend,tstart));
}
void gfs_ls(char mode, char *strParam){
	int 	    iStatus;
	GFS_item    listFilePtr= NULL;
	char 	    strGFSPath[MAXPARAMSLENGTH];
	
	//STEP 0: Process Param
	if(strParam == NULL && !strcmp(strParam, ""))
		strcpy(strGFSPath, strWorkingPath);
	else
		process_param(strParam, strGFSPath);

	//STEP 1: Get File List from Library and display*
	iStatus = gfs_read_dir(strGFSPath, &listFilePtr);	
	if(iStatus != GFS_SUCCESS) printf("|X| ls: %s \n", gfs_get_error(iStatus));
	else{
		GFS_item now=NULL;
		if (listFilePtr != NULL)
		{
			now = listFilePtr;
			while (now)
			{
				if(mode == 'd')
					printf("%s %s %8lld %s %s %s %s\n", now->type, now->permission, now->size, now->owner, now->created_date, now->modified_date, now->item_name);
				else 
					printf("%s \n", now->item_name);
				now=now->next;
			}
		}
	} 			
}
void gfs_cd(char *strParam){	
	//STEP 0: Check Param*
	if(!strcmp(strParam, "/")){
		strcpy(strWorkingPath, "/");
		return;
	}	
	else if(!strcmp(strParam, "..")){
		if (strcmp(strWorkingPath, "/")==0) 
			return;
			
		char *ptrLastCharOf;
		ptrLastCharOf = strrchr(strWorkingPath, '/');
		if ((ptrLastCharOf-strWorkingPath)==0) {
			strcpy(strWorkingPath, "/");
			return;
		}
		ptrLastCharOf[0] = 0x00;
		return;
	}	
	
	//STEP 1: Process Param 
	int     iStatus;
	char 	strGFSPath[MAXPARAMSLENGTH];
	
	process_param(strParam, strGFSPath);
	
	iStatus = gfs_check_dir(strGFSPath);
	if(iStatus != GFS_SUCCESS) printf("|X| cd: %s\n", gfs_get_error(iStatus));	
	else
		strcpy(strWorkingPath,strGFSPath);
}
void gfs_rm_f(char *strParam){
	int 	iStatus;
	char 	strGFSPath[MAXPARAMSLENGTH];
	
	//STEP 0: Process Param 
	process_param(strParam, strGFSPath);
	
	//STEP 1: DELETE*
	iStatus = gfs_remove_file(strGFSPath);
	if(iStatus != GFS_SUCCESS) printf("|X| rm: %s\n", gfs_get_error(iStatus));
}
void gfs_rm_d(char *strParam){
	int     iStatus;
	char 	strGFSPath[MAXPARAMSLENGTH];
	
	//STEP 0: Process Param 
	process_param(strParam, strGFSPath);
	
	//STEP 1: Remove Directory in current logical path*
	iStatus = gfs_remove_dir(strGFSPath);
	if(iStatus != GFS_SUCCESS) printf("|X| rmdir: %s\n", gfs_get_error(iStatus));
}
void gfs_rm_recrsv(char *strParam){
	int 	iStatus;
	char 	strGFSPath[MAXPARAMSLENGTH];
	
	//STEP 0: Process Param 
	process_param(strParam, strGFSPath);
	
	//STEP 1: DELETE RECURSIVE*
	iStatus = gfs_remove_recursive(strGFSPath);
	if(iStatus != GFS_SUCCESS) printf("|X| rm: %s\n", gfs_get_error(iStatus));
}
void gfs_mv(char *paramFrom, char *paramTo){
	int 	iStatus;
	char 	strSrcGFSPath[MAXPARAMSLENGTH];
	char 	strDstGFSPath[MAXPARAMSLENGTH];
	
	//STEP 0: Process Param 
	process_param(paramFrom, strSrcGFSPath);
	process_param(paramTo, strDstGFSPath);
	
	//STEP 1: MOVE*
	iStatus = gfs_move(strSrcGFSPath, strDstGFSPath);
	if(iStatus != GFS_SUCCESS) printf("|X| mv: %s\n", gfs_get_error(iStatus));
}
void gfs_mkdir(char *strParam){
	int 	iStatus;
	char 	strGFSPath[MAXPARAMSLENGTH];
	
	//STEP 0: Process Param 
	process_param(strParam, strGFSPath);
	
	//STEP 1: Create Directory in current logical path*
	iStatus = gfs_create_dir(strGFSPath);
	if(iStatus != GFS_SUCCESS) printf("|X| mkdir: %s\n", gfs_get_error(iStatus));
}
void gfs_debug(char *param){
	if(!strcmp(param, "on"))
		VERBOSE = 1;
	else if(!strcmp(param, "off"))
		VERBOSE = 0;
}
void gfs_show(char *param){
	if(!strcmp(param, "server")){
		printf("Checking server...\n");		
		
		//Define Variable
		GFS_server headPtr = NULL;
		
		//STEP 1: show available server*
	  	if(gfs_get_server(&headPtr) != GFS_FAILED){
	  		GFS_server now=NULL;
			if (headPtr != NULL)
			{
				now = headPtr;
				while (now)
				{				
					printf("GFS-server : %s | %lld/%lld | %s\n", now->hostname, now->used, now->total, now->online);
					now=now->next;
				}
			}
	  	}
	  	else  		
			printf("GFS-server: No Server available for this time.\n");
		}
}
void gfs_bash(char *param){
	system(param);
}
void gfs_chmod(char *mode, char *strParam){
	int 	iStatus;
	char 	strGFSPath[MAXPARAMSLENGTH];
	
	//STEP 0: Process Param 
	process_param(strParam, strGFSPath);
	
	//STEP 1: change permission mode*
	iStatus = gfs_change_mode(strGFSPath, mode);
	if(iStatus != GFS_SUCCESS) printf("|X| chmod: %s\n", gfs_get_error(iStatus));
}
void gfs_superuser(char *mode){
	if(!strcmp(mode, "on")){
		char strPswd[MAXPARAMSLENGTH];

		printf("insert password :");		
		getpswd(strPswd, MAXPARAMSLENGTH);
		if(gfs_SU_on(strPswd) != GFS_SUCCESS)
			printf("|X| SU: wrong password\n");	
	}
	else if(!strcmp(mode, "off")){
		gfs_SU_off();
	}
	else if(!strcmp(mode, "chpwd")){
		char strOldPswd[MAXPARAMSLENGTH];
		char strNewPswd1[MAXPARAMSLENGTH];
		char strNewPswd2[MAXPARAMSLENGTH];

		printf("insert old password :");
		getpswd(strOldPswd, MAXPARAMSLENGTH);
		if(gfs_SU_on(strOldPswd) != GFS_SUCCESS){
			printf("|X| SU: wrong password \n");	
			return;
		}

		int iMatch = 0;
		while(iMatch == 0){
			printf("insert new password :");
			getpswd(strNewPswd1, MAXPARAMSLENGTH);
			printf("verify new password :");
			getpswd(strNewPswd2, MAXPARAMSLENGTH);			
			// Validate Params
			if(strcmp(strNewPswd1, strNewPswd2))
				printf("|X| SU: password not matched\n");
			else iMatch =1;			
		}
				
		if(gfs_SU_change_pwd(strOldPswd, strNewPswd1) != GFS_SUCCESS)
				printf("|X| SU: failed changed password");
	}
}


// SOME FUNCTION //

/**********************************************************************************
* select_cmd : get index of command from global array 'arrComands'
* @params : String Command to compare with arrComands element 
* @return : Index of command
***********************************************************************************/
int select_cmd(char *strCmd) {
	int i;
	for (i=0; i < sizeof arrCommands/sizeof *arrCommands;	i++)
		if (!strcmp(strCmd, arrCommands[i]))
			return i;
	return -1;
}
/**********************************************************************************
* getchar_until_next : store char from getchar() to string (passing by reference)
* until space or new line
* @params : String to store, Max length of string 
* @return : The last getchar()
***********************************************************************************/
char getchar_until_next(char *strResult, int iMaxLength ){
	int iChar_count = 0;
	char chInput = getchar();
		while( (chInput != ' ') && (chInput != '\n') &&  (iChar_count < iMaxLength)) {
			strResult[iChar_count++] = chInput;
			chInput = getchar();
		}
		strResult[iChar_count] = 0x00; /* null terminate strCmd */
		return chInput;
}
/**********************************************************************************
* getchar_until_end : store char from getchar() to string (passing by reference)
* until new line (end of input line)
* @params : String to store, Max length of string 
* @return : void
***********************************************************************************/
void getchar_until_end(char *strResult, int iMaxLength){
	int iChar_count = 0;
	char chInput = getchar();
		while((chInput != '\n') &&  (iChar_count < iMaxLength)) {
			strResult[iChar_count++] = chInput;
			chInput = getchar();
		}
		strResult[iChar_count] = 0x00; /* null terminate strCmd */	
}		
/**********************************************************************************
* getchar_until_end : store char from getchar() to string (passing by reference)
* until new line (end of input line)
* @params : String to store, Max length of string 
* @return : void
***********************************************************************************/
void getpswd(char *strResult, int iMaxLength){
	int iChar_count = 0;
	char chInput = getchar();
		while((chInput != '\n') &&  (iChar_count < iMaxLength)) {
			strResult[iChar_count++] = chInput;
			chInput = getchar();
		}
		strResult[iChar_count] = 0x00; /* null terminate strCmd */	
}
/**********************************************************************************
* process_param : verify and check param input
* @params : String param that will be process
* @params : String logical location (passing by reference) 
* @params : String Item name (passing by reference) 
* @return : Index of command
***********************************************************************************/
void process_param(char *strParam, char *strGFSPath){
	//Define variable
	int iLength = strlen(strParam);
	char *pathPtr;	
	char strValidParam[iLength];
	
	// if no param
	if(strParam == NULL || !strcmp(strParam, "")){		
		strcpy(strGFSPath, strWorkingPath);
		return;
	}
	
	//Verify param	
	int i; int j=0; int flag=1;
	for(i=0; i<iLength; i++){
		// initiate flag
		if(strParam[i]=='/'){
			if((strParam[i+1]=='/') && (i < iLength-1))
				flag = 0;				
			else
				flag = 1;
		}	

		//check flag
		if(flag){
			strValidParam[j] = strParam[i];
			j++;
		}
	}
	strValidParam[j] = 0x00;	
	pathPtr = strrchr(strValidParam,'/');
	if(pathPtr-strValidParam == strlen(strValidParam)-1 && strcmp(strValidParam,"/")!=0)
		pathPtr[0] = 0x00;
	//*DEBUG*/printf("\n strValidParam: %s", strValidParam);
		
	// if param is root
	if(!strcmp(strValidParam, "/")){		
		strcpy(strGFSPath, "/");
		return;
	}
	
	//If param is from root
	if(strParam[0] == '/'){				
		strcpy(strGFSPath, strValidParam);
		return;
	}
	
	// initiate logical location
	strcpy(strGFSPath, strWorkingPath);
	
	// if param is item name
	pathPtr = strrchr(strValidParam,'/');
	if(pathPtr == NULL && strcmp(strValidParam,"..")){
		get_full_path(strWorkingPath, strValidParam, strGFSPath);
		return;
	}
			
	// begin process param
	char *cutPtr;	
	pathPtr = strtok(strValidParam,"/");
	while(pathPtr != NULL){
		if(!strcmp(pathPtr,"..")){
			if(!strcmp(strGFSPath,"/")){ 		//already in root			
				pathPtr = strtok(NULL, "/");
				continue;
			}
			cutPtr = strrchr(strGFSPath, '/');
			if(cutPtr-strGFSPath == 0)			//avoid delete root
			
				cutPtr[1] = 0x00;
			else
				cutPtr[0] = 0x00;
				
			// next
			pathPtr = strtok(NULL, "/");
		}
		else{
			if(strcmp(strGFSPath,"/")) //if not root
				strcat(strGFSPath, "/");
			strcat(strGFSPath, pathPtr);
			
			// next until end
			pathPtr = strtok(NULL, "\0");
		}					
	}
}
void get_file_name(char *strPath, char *strName_ref){	
    if(strPath == NULL || !strcmp(strPath,"")){
    	return;
        strcpy(strName_ref, "");
    }    
    char *namePtr;
    
    namePtr = strrchr(strPath, '/');
    if(namePtr != NULL)
        strcpy(strName_ref, namePtr+1);
    else
        strcpy(strName_ref, strPath);
}
void get_full_path(char *strLocation, char *strName, char *strFullPath_ref){
	
	strcpy(strFullPath_ref, strLocation);
	if(strcmp(strLocation,"/")) // not-root
		strcat(strFullPath_ref, "/");
	strcat(strFullPath_ref, strName);
}
void advance_cursor() {
  static int pos=0;
  char cursor[4]={'/','-','\\','|'};
  printf("\b%c", cursor[pos]);
  fflush(stdout);
  pos = (pos+1) % 4;
}

